home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / RCS / recipient.c,v < prev    next >
Encoding:
Text File  |  1991-08-08  |  24.0 KB  |  1,193 lines

  1. head    5.18;
  2. branch    5.18.0;
  3. access;
  4. symbols
  5.     RELEASE:5.18.0.12
  6.     BETA:5.18.0.13
  7.     UICSO:5.18.0
  8.     VANILLA:5.18;
  9. locks; strict;
  10. comment    @ * @;
  11.  
  12.  
  13. 5.18
  14. date    90.06.20.08.36.19;    author paul;    state Exp;
  15. branches
  16.     5.18.0.1;
  17. next    ;
  18.  
  19. 5.18.0.1
  20. date    90.06.20.09.43.51;    author paul;    state Exp;
  21. branches;
  22. next    5.18.0.2;
  23.  
  24. 5.18.0.2
  25. date    90.10.13.19.05.18;    author paul;    state Exp;
  26. branches;
  27. next    5.18.0.3;
  28.  
  29. 5.18.0.3
  30. date    90.10.17.12.42.32;    author paul;    state Exp;
  31. branches;
  32. next    5.18.0.4;
  33.  
  34. 5.18.0.4
  35. date    90.11.24.16.38.29;    author paul;    state Exp;
  36. branches;
  37. next    5.18.0.5;
  38.  
  39. 5.18.0.5
  40. date    90.11.26.20.37.34;    author paul;    state Exp;
  41. branches;
  42. next    5.18.0.6;
  43.  
  44. 5.18.0.6
  45. date    91.01.19.19.26.02;    author paul;    state Exp;
  46. branches;
  47. next    5.18.0.7;
  48.  
  49. 5.18.0.7
  50. date    91.02.15.20.14.07;    author paul;    state Exp;
  51. branches;
  52. next    5.18.0.8;
  53.  
  54. 5.18.0.8
  55. date    91.02.17.05.12.21;    author paul;    state Exp;
  56. branches;
  57. next    5.18.0.9;
  58.  
  59. 5.18.0.9
  60. date    91.03.04.22.24.00;    author paul;    state Exp;
  61. branches;
  62. next    5.18.0.10;
  63.  
  64. 5.18.0.10
  65. date    91.04.05.14.55.15;    author paul;    state Exp;
  66. branches;
  67. next    5.18.0.11;
  68.  
  69. 5.18.0.11
  70. date    91.06.06.19.44.06;    author paul;    state Exp;
  71. branches;
  72. next    5.18.0.12;
  73.  
  74. 5.18.0.12
  75. date    91.06.24.16.21.32;    author paul;    state Exp;
  76. branches;
  77. next    5.18.0.13;
  78.  
  79. 5.18.0.13
  80. date    91.08.08.22.13.13;    author paul;    state Exp;
  81. branches;
  82. next    ;
  83.  
  84.  
  85. desc
  86. @@
  87.  
  88.  
  89. 5.18
  90. log
  91. @5.64 Berkeley release
  92. @
  93. text
  94. @/*
  95.  * Copyright (c) 1983 Eric P. Allman
  96.  * Copyright (c) 1988 Regents of the University of California.
  97.  * All rights reserved.
  98.  *
  99.  * Redistribution and use in source and binary forms are permitted provided
  100.  * that: (1) source distributions retain this entire copyright notice and
  101.  * comment, and (2) distributions including binaries display the following
  102.  * acknowledgement:  ``This product includes software developed by the
  103.  * University of California, Berkeley and its contributors'' in the
  104.  * documentation or other materials provided with the distribution and in
  105.  * all advertising materials mentioning features or use of this software.
  106.  * Neither the name of the University nor the names of its contributors may
  107.  * be used to endorse or promote products derived from this software without
  108.  * specific prior written permission.
  109.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  110.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  111.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  112.  */
  113.  
  114. #ifndef lint
  115. static char sccsid[] = "@@(#)recipient.c    5.18 (Berkeley) 6/1/90";
  116. #endif /* not lint */
  117.  
  118. # include <sys/types.h>
  119. # include <sys/stat.h>
  120. # include <pwd.h>
  121. # include "sendmail.h"
  122.  
  123. /*
  124. **  SENDTOLIST -- Designate a send list.
  125. **
  126. **    The parameter is a comma-separated list of people to send to.
  127. **    This routine arranges to send to all of them.
  128. **
  129. **    Parameters:
  130. **        list -- the send list.
  131. **        ctladdr -- the address template for the person to
  132. **            send to -- effective uid/gid are important.
  133. **            This is typically the alias that caused this
  134. **            expansion.
  135. **        sendq -- a pointer to the head of a queue to put
  136. **            these people into.
  137. **
  138. **    Returns:
  139. **        none
  140. **
  141. **    Side Effects:
  142. **        none.
  143. */
  144.  
  145. # define MAXRCRSN    10
  146.  
  147. sendtolist(list, ctladdr, sendq)
  148.     char *list;
  149.     ADDRESS *ctladdr;
  150.     ADDRESS **sendq;
  151. {
  152.     register char *p;
  153.     register ADDRESS *al;    /* list of addresses to send to */
  154.     bool firstone;        /* set on first address sent */
  155.     bool selfref;        /* set if this list includes ctladdr */
  156.     char delimiter;        /* the address delimiter */
  157.  
  158.     if (tTd(25, 1))
  159.     {
  160.         printf("sendto: %s\n   ctladdr=", list);
  161.         printaddr(ctladdr, FALSE);
  162.     }
  163.  
  164.     /* heuristic to determine old versus new style addresses */
  165.     if (ctladdr == NULL &&
  166.         (index(list, ',') != NULL || index(list, ';') != NULL ||
  167.          index(list, '<') != NULL || index(list, '(') != NULL))
  168.         CurEnv->e_flags &= ~EF_OLDSTYLE;
  169.     delimiter = ' ';
  170.     if (!bitset(EF_OLDSTYLE, CurEnv->e_flags) || ctladdr != NULL)
  171.         delimiter = ',';
  172.  
  173.     firstone = TRUE;
  174.     selfref = FALSE;
  175.     al = NULL;
  176.  
  177.     for (p = list; *p != '\0'; )
  178.     {
  179.         register ADDRESS *a;
  180.         extern char *DelimChar;        /* defined in prescan */
  181.  
  182.         /* parse the address */
  183.         while (isspace(*p) || *p == ',')
  184.             p++;
  185.         a = parseaddr(p, (ADDRESS *) NULL, 1, delimiter);
  186.         p = DelimChar;
  187.         if (a == NULL)
  188.             continue;
  189.         a->q_next = al;
  190.         a->q_alias = ctladdr;
  191.  
  192.         /* see if this should be marked as a primary address */
  193.         if (ctladdr == NULL ||
  194.             (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags)))
  195.             a->q_flags |= QPRIMARY;
  196.  
  197.         /* put on send queue or suppress self-reference */
  198.         if (ctladdr != NULL && sameaddr(ctladdr, a))
  199.             selfref = TRUE;
  200.         else
  201.             al = a;
  202.         firstone = FALSE;
  203.     }
  204.  
  205.     /* if this alias doesn't include itself, delete ctladdr */
  206.     if (!selfref && ctladdr != NULL)
  207.         ctladdr->q_flags |= QDONTSEND;
  208.  
  209.     /* arrange to send to everyone on the local send list */
  210.     while (al != NULL)
  211.     {
  212.         register ADDRESS *a = al;
  213.         extern ADDRESS *recipient();
  214.  
  215.         al = a->q_next;
  216.         setctladdr(a);
  217.         a = recipient(a, sendq);
  218.  
  219.         /* arrange to inherit full name */
  220.         if (a->q_fullname == NULL && ctladdr != NULL)
  221.             a->q_fullname = ctladdr->q_fullname;
  222.     }
  223.  
  224.     CurEnv->e_to = NULL;
  225. }
  226. /*
  227. **  RECIPIENT -- Designate a message recipient
  228. **
  229. **    Saves the named person for future mailing.
  230. **
  231. **    Parameters:
  232. **        a -- the (preparsed) address header for the recipient.
  233. **        sendq -- a pointer to the head of a queue to put the
  234. **            recipient in.  Duplicate supression is done
  235. **            in this queue.
  236. **
  237. **    Returns:
  238. **        The actual address in the queue.  This will be "a" if
  239. **        the address is not a duplicate, else the original address.
  240. **
  241. **    Side Effects:
  242. **        none.
  243. */
  244.  
  245. ADDRESS *
  246. recipient(a, sendq)
  247.     register ADDRESS *a;
  248.     register ADDRESS **sendq;
  249. {
  250.     register ADDRESS *q;
  251.     ADDRESS **pq;
  252.     register struct mailer *m;
  253.     register char *p;
  254.     bool quoted = FALSE;        /* set if the addr has a quote bit */
  255.     char buf[MAXNAME];        /* unquoted image of the user name */
  256.     extern ADDRESS *getctladdr();
  257.     extern bool safefile();
  258.  
  259.     CurEnv->e_to = a->q_paddr;
  260.     m = a->q_mailer;
  261.     errno = 0;
  262.     if (tTd(26, 1))
  263.     {
  264.         printf("\nrecipient: ");
  265.         printaddr(a, FALSE);
  266.     }
  267.  
  268.     /* break aliasing loops */
  269.     if (AliasLevel > MAXRCRSN)
  270.     {
  271.         usrerr("aliasing/forwarding loop broken");
  272.         return (a);
  273.     }
  274.  
  275.     /*
  276.     **  Finish setting up address structure.
  277.     */
  278.  
  279.     /* set the queue timeout */
  280.     a->q_timeout = TimeOut;
  281.  
  282.     /* map user & host to lower case if requested on non-aliases */
  283.     if (a->q_alias == NULL)
  284.         loweraddr(a);
  285.  
  286.     /* get unquoted user for file, program or user.name check */
  287.     (void) strcpy(buf, a->q_user);
  288.     for (p = buf; *p != '\0' && !quoted; p++)
  289.     {
  290.         if (!isascii(*p) && (*p & 0377) != (SpaceSub & 0377))
  291.             quoted = TRUE;
  292.     }
  293.     stripquotes(buf, TRUE);
  294.  
  295.     /* do sickly crude mapping for program mailing, etc. */
  296.     if (m == LocalMailer && buf[0] == '|')
  297.     {
  298.         a->q_mailer = m = ProgMailer;
  299.         a->q_user++;
  300.         if (a->q_alias == NULL && !QueueRun && !ForceMail)
  301.         {
  302.             a->q_flags |= QDONTSEND|QBADADDR;
  303.             usrerr("Cannot mail directly to programs");
  304.         }
  305.     }
  306.  
  307.     /*
  308.     **  Look up this person in the recipient list.
  309.     **    If they are there already, return, otherwise continue.
  310.     **    If the list is empty, just add it.  Notice the cute
  311.     **    hack to make from addresses suppress things correctly:
  312.     **    the QDONTSEND bit will be set in the send list.
  313.     **    [Please note: the emphasis is on "hack."]
  314.     */
  315.  
  316.     for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
  317.     {
  318.         if (!ForceMail && sameaddr(q, a))
  319.         {
  320.             if (tTd(26, 1))
  321.             {
  322.                 printf("%s in sendq: ", a->q_paddr);
  323.                 printaddr(q, FALSE);
  324.             }
  325.             if (!bitset(QDONTSEND, a->q_flags))
  326.                 message(Arpa_Info, "duplicate suppressed");
  327.             if (!bitset(QPRIMARY, q->q_flags))
  328.                 q->q_flags |= a->q_flags;
  329.             return (q);
  330.         }
  331.     }
  332.  
  333.     /* add address on list */
  334.     *pq = a;
  335.     a->q_next = NULL;
  336.     CurEnv->e_nrcpts++;
  337.  
  338.     /*
  339.     **  Alias the name and handle :include: specs.
  340.     */
  341.  
  342.     if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags))
  343.     {
  344.         if (strncmp(a->q_user, ":include:", 9) == 0)
  345.         {
  346.             a->q_flags |= QDONTSEND;
  347.             if (a->q_alias == NULL && !QueueRun && !ForceMail)
  348.             {
  349.                 a->q_flags |= QBADADDR;
  350.                 usrerr("Cannot mail directly to :include:s");
  351.             }
  352.             else
  353.             {
  354.                 message(Arpa_Info, "including file %s", &a->q_user[9]);
  355.                 include(&a->q_user[9], " sending", a, sendq);
  356.             }
  357.         }
  358.         else
  359.             alias(a, sendq);
  360.     }
  361.  
  362.     /*
  363.     **  If the user is local and still being sent, verify that
  364.     **  the address is good.  If it is, try to forward.
  365.     **  If the address is already good, we have a forwarding
  366.     **  loop.  This can be broken by just sending directly to
  367.     **  the user (which is probably correct anyway).
  368.     */
  369.  
  370.     if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer)
  371.     {
  372.         struct stat stb;
  373.         extern bool writable();
  374.  
  375.         /* see if this is to a file */
  376.         if (buf[0] == '/')
  377.         {
  378.             p = rindex(buf, '/');
  379.             /* check if writable or creatable */
  380.             if (a->q_alias == NULL && !QueueRun && !ForceMail)
  381.             {
  382.                 a->q_flags |= QDONTSEND|QBADADDR;
  383.                 usrerr("Cannot mail directly to files");
  384.             }
  385.             else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) :
  386.                 (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC)))
  387.             {
  388.                 a->q_flags |= QBADADDR;
  389.                 giveresponse(EX_CANTCREAT, m, CurEnv);
  390.             }
  391.         }
  392.         else
  393.         {
  394.             register struct passwd *pw;
  395.             extern struct passwd *finduser();
  396.  
  397.             /* warning -- finduser may trash buf */
  398.             pw = finduser(buf);
  399.             if (pw == NULL)
  400.             {
  401.                 a->q_flags |= QBADADDR;
  402.                 giveresponse(EX_NOUSER, m, CurEnv);
  403.             }
  404.             else
  405.             {
  406.                 char nbuf[MAXNAME];
  407.  
  408.                 if (strcmp(a->q_user, pw->pw_name) != 0)
  409.                 {
  410.                     a->q_user = newstr(pw->pw_name);
  411.                     (void) strcpy(buf, pw->pw_name);
  412.                 }
  413.                 a->q_home = newstr(pw->pw_dir);
  414.                 a->q_uid = pw->pw_uid;
  415.                 a->q_gid = pw->pw_gid;
  416.                 a->q_flags |= QGOODUID;
  417.                 buildfname(pw->pw_gecos, pw->pw_name, nbuf);
  418.                 if (nbuf[0] != '\0')
  419.                     a->q_fullname = newstr(nbuf);
  420.                 if (!quoted)
  421.                     forward(a, sendq);
  422.             }
  423.         }
  424.     }
  425.     return (a);
  426. }
  427. /*
  428. **  FINDUSER -- find the password entry for a user.
  429. **
  430. **    This looks a lot like getpwnam, except that it may want to
  431. **    do some fancier pattern matching in /etc/passwd.
  432. **
  433. **    This routine contains most of the time of many sendmail runs.
  434. **    It deserves to be optimized.
  435. **
  436. **    Parameters:
  437. **        name -- the name to match against.
  438. **
  439. **    Returns:
  440. **        A pointer to a pw struct.
  441. **        NULL if name is unknown or ambiguous.
  442. **
  443. **    Side Effects:
  444. **        may modify name.
  445. */
  446.  
  447. struct passwd *
  448. finduser(name)
  449.     char *name;
  450. {
  451.     register struct passwd *pw;
  452.     register char *p;
  453.     extern struct passwd *getpwent();
  454.     extern struct passwd *getpwnam();
  455.  
  456.     /* map upper => lower case */
  457.     for (p = name; *p != '\0'; p++)
  458.     {
  459.         if (isascii(*p) && isupper(*p))
  460.             *p = tolower(*p);
  461.     }
  462.  
  463.     /* look up this login name using fast path */
  464.     if ((pw = getpwnam(name)) != NULL)
  465.         return (pw);
  466.  
  467.     /* search for a matching full name instead */
  468.     for (p = name; *p != '\0'; p++)
  469.     {
  470.         if (*p == (SpaceSub & 0177) || *p == '_')
  471.             *p = ' ';
  472.     }
  473.     (void) setpwent();
  474.     while ((pw = getpwent()) != NULL)
  475.     {
  476.         char buf[MAXNAME];
  477.  
  478.         buildfname(pw->pw_gecos, pw->pw_name, buf);
  479.         if (index(buf, ' ') != NULL && !strcasecmp(buf, name))
  480.         {
  481.             message(Arpa_Info, "sending to login name %s", pw->pw_name);
  482.             return (pw);
  483.         }
  484.     }
  485.     return (NULL);
  486. }
  487. /*
  488. **  WRITABLE -- predicate returning if the file is writable.
  489. **
  490. **    This routine must duplicate the algorithm in sys/fio.c.
  491. **    Unfortunately, we cannot use the access call since we
  492. **    won't necessarily be the real uid when we try to
  493. **    actually open the file.
  494. **
  495. **    Notice that ANY file with ANY execute bit is automatically
  496. **    not writable.  This is also enforced by mailfile.
  497. **
  498. **    Parameters:
  499. **        s -- pointer to a stat struct for the file.
  500. **
  501. **    Returns:
  502. **        TRUE -- if we will be able to write this file.
  503. **        FALSE -- if we cannot write this file.
  504. **
  505. **    Side Effects:
  506. **        none.
  507. */
  508.  
  509. bool
  510. writable(s)
  511.     register struct stat *s;
  512. {
  513.     int euid, egid;
  514.     int bits;
  515.  
  516.     if (bitset(0111, s->st_mode))
  517.         return (FALSE);
  518.     euid = getruid();
  519.     egid = getrgid();
  520.     if (geteuid() == 0)
  521.     {
  522.         if (bitset(S_ISUID, s->st_mode))
  523.             euid = s->st_uid;
  524.         if (bitset(S_ISGID, s->st_mode))
  525.             egid = s->st_gid;
  526.     }
  527.  
  528.     if (euid == 0)
  529.         return (TRUE);
  530.     bits = S_IWRITE;
  531.     if (euid != s->st_uid)
  532.     {
  533.         bits >>= 3;
  534.         if (egid != s->st_gid)
  535.             bits >>= 3;
  536.     }
  537.     return ((s->st_mode & bits) != 0);
  538. }
  539. /*
  540. **  INCLUDE -- handle :include: specification.
  541. **
  542. **    Parameters:
  543. **        fname -- filename to include.
  544. **        msg -- message to print in verbose mode.
  545. **        ctladdr -- address template to use to fill in these
  546. **            addresses -- effective user/group id are
  547. **            the important things.
  548. **        sendq -- a pointer to the head of the send queue
  549. **            to put these addresses in.
  550. **
  551. **    Returns:
  552. **        none.
  553. **
  554. **    Side Effects:
  555. **        reads the :include: file and sends to everyone
  556. **        listed in that file.
  557. */
  558.  
  559. include(fname, msg, ctladdr, sendq)
  560.     char *fname;
  561.     char *msg;
  562.     ADDRESS *ctladdr;
  563.     ADDRESS **sendq;
  564. {
  565.     char buf[MAXLINE];
  566.     register FILE *fp;
  567.     char *oldto = CurEnv->e_to;
  568.     char *oldfilename = FileName;
  569.     int oldlinenumber = LineNumber;
  570.  
  571.     fp = fopen(fname, "r");
  572.     if (fp == NULL)
  573.     {
  574.         usrerr("Cannot open %s", fname);
  575.         return;
  576.     }
  577.     if (getctladdr(ctladdr) == NULL)
  578.     {
  579.         struct stat st;
  580.  
  581.         if (fstat(fileno(fp), &st) < 0)
  582.             syserr("Cannot fstat %s!", fname);
  583.         ctladdr->q_uid = st.st_uid;
  584.         ctladdr->q_gid = st.st_gid;
  585.         ctladdr->q_flags |= QGOODUID;
  586.     }
  587.  
  588.     /* read the file -- each line is a comma-separated list. */
  589.     FileName = fname;
  590.     LineNumber = 0;
  591.     while (fgets(buf, sizeof buf, fp) != NULL)
  592.     {
  593.         register char *p = index(buf, '\n');
  594.  
  595.         LineNumber++;
  596.         if (p != NULL)
  597.             *p = '\0';
  598.         if (buf[0] == '\0')
  599.             continue;
  600.         CurEnv->e_to = oldto;
  601.         message(Arpa_Info, "%s to %s", msg, buf);
  602.         AliasLevel++;
  603.         sendtolist(buf, ctladdr, sendq);
  604.         AliasLevel--;
  605.     }
  606.  
  607.     (void) fclose(fp);
  608.     FileName = oldfilename;
  609.     LineNumber = oldlinenumber;
  610. }
  611. /*
  612. **  SENDTOARGV -- send to an argument vector.
  613. **
  614. **    Parameters:
  615. **        argv -- argument vector to send to.
  616. **
  617. **    Returns:
  618. **        none.
  619. **
  620. **    Side Effects:
  621. **        puts all addresses on the argument vector onto the
  622. **            send queue.
  623. */
  624.  
  625. sendtoargv(argv)
  626.     register char **argv;
  627. {
  628.     register char *p;
  629.  
  630.     while ((p = *argv++) != NULL)
  631.     {
  632.         if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at"))
  633.         {
  634.             char nbuf[MAXNAME];
  635.  
  636.             if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf)
  637.                 usrerr("address overflow");
  638.             else
  639.             {
  640.                 (void) strcpy(nbuf, p);
  641.                 (void) strcat(nbuf, "@@");
  642.                 (void) strcat(nbuf, argv[1]);
  643.                 p = newstr(nbuf);
  644.                 argv += 2;
  645.             }
  646.         }
  647.         sendtolist(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
  648.     }
  649. }
  650. /*
  651. **  GETCTLADDR -- get controlling address from an address header.
  652. **
  653. **    If none, get one corresponding to the effective userid.
  654. **
  655. **    Parameters:
  656. **        a -- the address to find the controller of.
  657. **
  658. **    Returns:
  659. **        the controlling address.
  660. **
  661. **    Side Effects:
  662. **        none.
  663. */
  664.  
  665. ADDRESS *
  666. getctladdr(a)
  667.     register ADDRESS *a;
  668. {
  669.     while (a != NULL && !bitset(QGOODUID, a->q_flags))
  670.         a = a->q_alias;
  671.     return (a);
  672. }
  673. @
  674.  
  675.  
  676. 5.18.0.1
  677. log
  678. @IDA patches
  679. @
  680. text
  681. @a308 1
  682.                 errno = 0;    /* no special error */
  683. a353 3
  684. #define WORST_MATCH    -2        /* even worse than no match */
  685. #define NO_UID        -999        /* any "impossible" uid will do */
  686.  
  687. a359 2
  688.     int best_match = WORST_MATCH;
  689.     int best_uid = NO_UID;
  690. a361 1
  691.     extern struct passwd *getpwuid();
  692. a362 2
  693.     errno = 0;
  694.  
  695. a368 3
  696.     if (tTd(26, 6))
  697.         printf("%s password entry for \"%s\"\n",
  698.                getpwnam(name) ? "found" : "can't find", name);
  699. d373 7
  700. a379 2
  701.     if (tTd(26, 6))
  702.         printf("looking for partial match to \"%s\"\n", name);
  703. a383 1
  704.         register int this_match;
  705. a384 7
  706.         if (strcasecmp(pw->pw_name, name) == 0) {
  707.             if (tTd(26, 6))
  708.             printf("found password entry for \"%s\" as \"%s\"\n",
  709.                    name, pw->pw_name);
  710.             return (pw);
  711.         }
  712.  
  713. d386 2
  714. a387 26
  715.         this_match = partialstring(buf, name);
  716.         if (tTd(26, 6) && this_match >= 0)
  717.             printf("matched on level %d with \"%s\"\n",
  718.                    this_match, buf);
  719.         if (this_match < best_match)
  720.             continue;
  721.         else if (this_match > best_match) {
  722.             best_match = this_match;
  723.             best_uid = pw->pw_uid;
  724.         }
  725.         else if (best_uid != pw->pw_uid)
  726.             best_uid = NO_UID;
  727.     }
  728.     if (tTd(26, 6)) {
  729.         if (best_match == WORST_MATCH)
  730.             printf("no match, failing...\n");
  731.         else if (best_uid == NO_UID)
  732.             printf("ambiguous match, failing...\n");
  733.         else
  734.             printf("succeding on level %d...\n",
  735.                    best_match);
  736.     }
  737.     if (best_uid == NO_UID)
  738.         return (NULL);
  739.  
  740.     pw = getpwuid(best_uid);
  741. a389 48
  742. }
  743. /*
  744. **  PARTIALSTRING -- is one string of words contained by another?
  745. **
  746. **    See if one string of words can be found as part of
  747. **    another string of words.  All substrings delimited by
  748. **    one or more non-alphanumeric characters are considered
  749. **    "words", and a partial match is such that all the words
  750. **    of the pattern string are either full prefixes
  751. **    of the target string.  Upper or lower case letters are
  752. **    considered equal.
  753. **
  754. **    Parameters:
  755. **        target -- target string
  756. **        pattern -- pattern string
  757. **
  758. **    Returns:
  759. **        The number of fully matched words, or -1 if none.
  760. **
  761. **    Side Effects:
  762. **        None.
  763. **
  764. */
  765.  
  766. partialstring(target, pattern)
  767.     char *target;
  768.     char *pattern;
  769. {
  770.     register char *t, *p, *q;
  771.     int full_words = 0;
  772.  
  773.     /* skip initial delimiters */
  774.     for (t = target; *t != '\0' && !isalnum(*t); t++);
  775.     for (p = pattern; *p != '\0' && !isalnum(*p); p++);
  776.     q = p;
  777.  
  778.     while (*t != '\0' && *p != '\0') {
  779.     /*
  780.      * if at end of pattern word, find next, remember it,
  781.      * and eat the current target word
  782.      */
  783.     if (!isalnum(*p)) {
  784.         while (*p != '\0' && !isalnum(*p)) p++;
  785.         if (*p == '\0')
  786.         continue;
  787.         q = p;
  788.         if (!isalnum(*t)) {
  789.         full_words++;
  790. a390 3
  791.         while (*t != '\0' && isalnum(*t)) t++;
  792.         while (*t != '\0' && !isalnum(*t)) t++;
  793.         continue;
  794. d392 1
  795. a392 26
  796.  
  797.     /*
  798.      * if match, advance both pointers
  799.      */
  800.     if ((isupper(*t) ? tolower(*t) : *t) ==
  801.         (isupper(*p) ? tolower(*p) : *p)) {
  802.         t++, p++;
  803.         continue;
  804.     }
  805.  
  806.     /*
  807.      * if no match, backtrack to last unmatched pattern word and
  808.      * eat current target word
  809.      */
  810.     p = q;
  811.     while (*t != '\0' && isalnum(*t)) t++;
  812.     while (*t != '\0' && !isalnum(*t)) t++;
  813.     }
  814.  
  815.     /*
  816.      * now, the pattern should be fully consumed if there was a match
  817.      */
  818.     if (*p == '\0')
  819.     return isalnum(*t) ? full_words : full_words + 1;
  820.     else
  821.     return -1;
  822. @
  823.  
  824.  
  825. 5.18.0.2
  826. log
  827. @Bruce Lilly (bruce%balilly@@sonyd1.broadcast.sony.com) provided patch for
  828. ignoring null and # comment lines in .forward files.
  829. @
  830. text
  831. @a591 1
  832.     extern ADDRESS *getctladdr();
  833. d620 1
  834. a620 3
  835.  
  836.         /* ignore null lines and # comment lines */
  837.         if ((buf[0] == '\0') || (buf[0] == '#'))
  838. @
  839.  
  840.  
  841. 5.18.0.3
  842. log
  843. @Added #ifdef/#define FUZZY to control whether fuzzy matching of local
  844. @
  845. text
  846. @a384 4
  847. #ifndef FUZZY
  848.     else
  849.         return (NULL);
  850. #else /* FUZZY */
  851. d399 1
  852. a428 1
  853. #endif /* !FUZZY */
  854. a452 1
  855. #ifdef FUZZY
  856. a508 1
  857. #endif /* FUZZY */
  858. @
  859.  
  860.  
  861. 5.18.0.4
  862. log
  863. @Deleted getpwuid() declaration.
  864. @
  865. text
  866. @d368 1
  867. @
  868.  
  869.  
  870. 5.18.0.5
  871. log
  872. @Added a pair of #ifdef/#endif FUZZY.
  873. @
  874. text
  875. @a363 1
  876. #ifdef FUZZY
  877. a365 1
  878. #endif /* FUZZY */
  879. @
  880.  
  881.  
  882. 5.18.0.6
  883. log
  884. @Deleted #include <sys/types.h> as it's already included via sendmail.h from
  885. useful.h.  #include "sendmail.h" relocated to top of #include list.
  886. @
  887. text
  888. @d25 1
  889. a25 1
  890. # include "sendmail.h"
  891. d28 1
  892. @
  893.  
  894.  
  895. 5.18.0.7
  896. log
  897. @Bulletproofing for POSIX.
  898. @
  899. text
  900. @d25 3
  901. a27 9
  902. #include "sendmail.h"
  903. #include <sys/stat.h>
  904. #include <pwd.h>
  905. #ifndef S_IEXEC
  906. # define    S_IEXEC        _S_IEXEC
  907. #endif /* !S_IEXEC */
  908. #ifndef S_IWRITE
  909. # define    S_IWRITE    _S_IWRITE
  910. #endif /* !S_IWRITE */
  911. @
  912.  
  913.  
  914. 5.18.0.8
  915. log
  916. @Added static keyword for declaration of writable(), finduser(), and
  917. partialstring().
  918. @
  919. text
  920. @d285 1
  921. a285 1
  922.         static bool writable();
  923. d307 1
  924. a307 1
  925.             static struct passwd *finduser();
  926. d363 1
  927. a363 1
  928. static struct passwd *
  929. a401 1
  930.         static partialstring();
  931. a463 1
  932. static
  933. d543 1
  934. a543 1
  935. static bool
  936. @
  937.  
  938.  
  939. 5.18.0.9
  940. log
  941. @ANSIfied.
  942. @
  943. text
  944. @a34 10
  945. #ifdef __STDC__
  946. static struct passwd * finduser(char *);
  947. static partialstring(const char *, const char *);
  948. static bool writable(struct stat *);
  949. #else /* !__STDC__ */
  950. static struct passwd * finduser();
  951. static partialstring();
  952. static bool writable();
  953. #endif /* __STDC__ */
  954.  
  955. a58 1
  956. void
  957. d60 1
  958. a60 1
  959.     const char *list;
  960. d64 1
  961. a64 1
  962.     register const char *p;
  963. d97 1
  964. a97 1
  965.         a = parseaddr((char *)p, (ADDRESS *) NULL, 1, delimiter);
  966. d125 1
  967. d168 2
  968. d285 1
  969. d307 1
  970. d373 2
  971. d402 1
  972. d467 2
  973. a468 1
  974.     const char *target, *pattern;
  975. d474 2
  976. a475 2
  977.     for (t = (char *)target; *t != '\0' && !isalnum(*t); t++);
  978.     for (p = (char *)pattern; *p != '\0' && !isalnum(*p); p++);
  979. a594 1
  980. void
  981. d596 2
  982. a597 1
  983.     const char *fname, *msg;
  984. d606 1
  985. d626 1
  986. a626 1
  987.     FileName = (char *)fname;
  988. a663 1
  989. void
  990. @
  991.  
  992.  
  993. 5.18.0.10
  994. log
  995. @Added RCS ID string
  996. @
  997. text
  998. @a22 1
  999. static char  rcsid[] = "@@(#)$Id$";
  1000. @
  1001.  
  1002.  
  1003. 5.18.0.11
  1004. log
  1005. @Fix handling of multi-line .forward files from Eric Wassenaar
  1006. (e07@@nikhefh.nikhef.nl).  Formatting of partialstring() fixed up.
  1007. @
  1008. text
  1009. @d22 2
  1010. a23 2
  1011. static char sccsid[] = "@@(#)recipient.c    5.18 (Berkeley) 6/1/90    %I% local";
  1012. static char  rcsid[] = "@@(#)$Id: recipient.c,v 5.18.0.15 1991/06/05 02:20:56 paul Exp paul $";
  1013. d38 1
  1014. a38 1
  1015. static int partialstring(const char *, const char *);
  1016. d42 1
  1017. a42 1
  1018. static int partialstring();
  1019. d130 2
  1020. a131 2
  1021.     if (selfref && ctladdr != NULL)
  1022.         ctladdr->q_flags |= QSELFREF;
  1023. d408 1
  1024. a408 2
  1025.         if (strcasecmp(pw->pw_name, name) == 0)
  1026.         {
  1027. d421 1
  1028. a421 2
  1029.         else if (this_match > best_match)
  1030.         {
  1031. d428 1
  1032. a428 2
  1033.     if (tTd(26, 6))
  1034.     {
  1035. d469 1
  1036. a469 1
  1037. static int
  1038. d471 1
  1039. a471 1
  1040.     const char *target, *pattern;
  1041. d473 2
  1042. a474 2
  1043.     register char *t, *p, *q;
  1044.     int full_words = 0;
  1045. d476 4
  1046. a479 28
  1047.     /* skip initial delimiters */
  1048.     for (t = (char *)target; *t != '\0' && !isalnum(*t); t++)
  1049.         ;
  1050.     for (p = (char *)pattern; *p != '\0' && !isalnum(*p); p++)
  1051.         ;
  1052.     q = p;
  1053.  
  1054.     while (*t != '\0' && *p != '\0')
  1055.     {
  1056.         /*
  1057.          * if at end of pattern word, find next, remember it,
  1058.          * and eat the current target word
  1059.          */
  1060.         if (!isalnum(*p))
  1061.         {
  1062.             while (*p != '\0' && !isalnum(*p))
  1063.                 p++;
  1064.             if (*p == '\0')
  1065.                 continue;
  1066.             q = p;
  1067.             if (!isalnum(*t))
  1068.                 full_words++;
  1069.             while (*t != '\0' && isalnum(*t))
  1070.                 t++;
  1071.             while (*t != '\0' && !isalnum(*t))
  1072.                 t++;
  1073.             continue;
  1074.         }
  1075. d481 12
  1076. a492 8
  1077.         /*
  1078.          * if match, advance both pointers
  1079.          */
  1080.         if ((isupper(*t) ? tolower(*t) : *t) ==
  1081.             (isupper(*p) ? tolower(*p) : *p))
  1082.         {
  1083.             t++, p++;
  1084.             continue;
  1085. d494 4
  1086. d499 7
  1087. a505 9
  1088.         /*
  1089.          * if no match, backtrack to last unmatched pattern word and
  1090.          * eat current target word.
  1091.          */
  1092.         p = q;
  1093.         while (*t != '\0' && isalnum(*t))
  1094.             t++;
  1095.         while (*t != '\0' && !isalnum(*t))
  1096.             t++;
  1097. d509 2
  1098. a510 1
  1099.      * now, the pattern should be fully consumed if there was a match
  1100. d512 12
  1101. a523 4
  1102.     if (*p == '\0')
  1103.         return (isalnum(*t) ? full_words : full_words + 1);
  1104.     else
  1105.         return (-1);
  1106. a608 1
  1107.     bool included = FALSE;
  1108. a644 1
  1109.         included = TRUE;
  1110. a647 2
  1111.     if (included && !bitset(QSELFREF, ctladdr->q_flags))
  1112.         ctladdr->q_flags |= QDONTSEND;
  1113. @
  1114.  
  1115.  
  1116. 5.18.0.12
  1117. log
  1118. @Bruce Lilly contributed patch to first try user names as given, then as
  1119. all lower-case (using makelower()).
  1120. @
  1121. text
  1122. @d22 2
  1123. a23 2
  1124. static char sccsid[] = "@@(#)recipient.c    5.18 (Berkeley) 6/1/90";
  1125. static char  rcsid[] = "@@(#)$Id: recipient.c,v 5.18.0.11 1991/06/06 19:44:06 paul Exp paul $";
  1126. d375 1
  1127. d383 2
  1128. a384 2
  1129.     /* first try name as given */
  1130.     if ((pw = getpwnam(name)) == NULL)
  1131. d386 2
  1132. a387 5
  1133.         /* try again as lower-case */
  1134.         char *lowname = newstr(name);
  1135.         makelower(lowname);
  1136.         pw = getpwnam(lowname);
  1137.         free(lowname);
  1138. a388 1
  1139.  
  1140. d391 1
  1141. a391 1
  1142.                pw ? "found" : "can't find", name);
  1143. d393 3
  1144. d397 2
  1145. a398 1
  1146.     return (pw);
  1147. a399 3
  1148.     if (pw != NULL)
  1149.         return (pw);
  1150.  
  1151. @
  1152.  
  1153.  
  1154. 5.18.0.13
  1155. log
  1156. @From: e07@@nikhefh.nikhef.nl (Eric Wassenaar)
  1157. Date: 22 Jul 91 14:40:21 GMT
  1158. Newsgroup: comp.mail.sendmail
  1159. Subject: Re: sendmail-5.65c+IDA-1.4.4 - Double delivery problem
  1160.  
  1161. This is a slight amendment to the patch of Neil Rickert.
  1162. It involves no functional change, only a simple change of
  1163. the place where the QSELFREF flag is reset.
  1164. Blame me for having overlooked this one in the original patch.
  1165.  
  1166. The memory of self-reference is needed only within the scope
  1167. of the routines alias() and include(). It is therefore best
  1168. to reset the QSELFREF bit in the beginning of those routines
  1169. itself to make calls to them independent.
  1170.  
  1171. As already has been pointed out, it must not be done within
  1172. sendtolist() since that would nullify the effect for which
  1173. this flag was introduced. (The flag should be carried over
  1174. across the multiple calls of sendtolist() in the loop in
  1175. the include() routine.)
  1176.  
  1177. Eric Wassenaar
  1178. --
  1179. Organization: NIKHEF-H, National Institute for Nuclear and High-Energy Physics
  1180. Address: Kruislaan 409, P.O. Box 41882, 1009 DB Amsterdam, the Netherlands
  1181. Phone: +31 20 592 0412, Home: +31 20 6909449, Telefax: +31 20 592 5155
  1182. Internet: e07@@nikhef.nl
  1183. @
  1184. text
  1185. @d23 1
  1186. a23 1
  1187. static char  rcsid[] = "@@(#)$Id: recipient.c,v 5.18.0.12 1991/06/24 16:21:32 paul Exp paul $";
  1188. a640 3
  1189.  
  1190.     /* sendtolist() detects possible self-refs in any line of this file */
  1191.     ctladdr->q_flags &= ~QSELFREF;
  1192. @
  1193.